package com.javaxiaobear.base.framework.redisson;

import cn.hutool.core.collection.CollUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fory.Fory;
import org.apache.fory.ThreadSafeFory;
import org.apache.fory.config.ForyBuilder;
import org.apache.fory.config.Language;
import org.redisson.client.codec.BaseCodec;
import org.redisson.client.protocol.Decoder;
import org.redisson.client.protocol.Encoder;

@RequiredArgsConstructor
public class ForyCodec extends BaseCodec {

  public static ForyCodec INSTANCE = new ForyCodec();

  private final ThreadSafeFory fory;

  public ForyCodec() {
    this(null, null, Language.JAVA);
  }

  public ForyCodec(ClassLoader classLoader, Set<String> allowedClasses, Language language) {
    // 这里缺少对mediaType的检测
    ForyBuilder builder = Fory.builder();
    if (classLoader != null) {
      builder.withClassLoader(classLoader);
    }
    builder.withLanguage(language);
    builder.requireClassRegistration(CollUtil.isNotEmpty(allowedClasses));

    builder.withIntCompressed(true);
    builder.withLongCompressed(true);
    builder.withStringCompressed(true);
    builder.withNumberCompressed(true);

    fory = builder.buildThreadSafeForyPool(4, 512);

    if (CollUtil.isNotEmpty(allowedClasses))
      for (String allowedClass : allowedClasses) {
        try {
          fory.register(Class.forName(allowedClass));
        } catch (ClassNotFoundException e) {
          throw new IllegalStateException(e);
        }
      }
  }

  @Override
  public Decoder<Object> getValueDecoder() {
    return (buf, state) -> {
      byte[] bytes = new byte[buf.readableBytes()];
      buf.readBytes(bytes);
      return fory.deserialize(bytes);
    };
  }

  @Override
  public Encoder getValueEncoder() {
    return in -> {
      ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
      out.writeBytes(fory.serialize(in));
      return out;
    };
  }
}
